#define RAYGUI_IMPLEMENTATION
#include <raygui.h>
#define RPAK_IMPLEMENTATION
#include "rpak.h"

#include "toolbar.h"
#include "statusbar.h"
#include "table.h"
#include "dialog.h"
#include "msgbox.h"
#include "subwindow.h"

#ifdef __cplusplus
extern "C"
{
#endif // __cplusplus

const char *toolName = "rpaker";
const char *toolVersion = "1.0.1";
char pak[128];
unsigned int fileCount = 0;
rpakFileInfo *files = { 0 };

//--------------------------------------------------------------------------------
// msgbox work
//--------------------------------------------------------------------------------
void createPackage(unsigned int *count, unsigned int *selected)
{
	*count = 0;
	files = realloc(files, 0);
	*selected = 0;

	if (TextLength(pak) > 0)
		TextCopy(pak, "");

	SetWindowTitle(TextFormat("%s v%s", toolName, toolVersion));
}

void deleteFile(unsigned int *count, unsigned int *selected)
{
	if (*selected != *count - 1) // 不是最后一个数据
	{
		for (int i = *selected; i < *count - 1; i++)
			files[i] = files[i + 1];
	}
	(*count)--;
	files = realloc(files, *count * sizeof(rpakFileInfo));
	*selected = 0;

	if (TextLength(pak) > 0)
		SetWindowTitle(TextFormat("%s v%s - %s*", toolName, toolVersion, pak));
}
//--------------------------------------------------------------------------------

//--------------------------------------------------------------------------------
// dialog work: return true = show dialog, false = close dialog
//--------------------------------------------------------------------------------
bool openPackage(const char *dir, const char *file)
{
	const char *f = TextFormat("%s%c%s", dir, osSlash, file);

	if (IsFileExtension(f, RPAK_FILEEXT_INDEX) && FileExists(f))
	{
		TextCopy(pak, TextFormat("%s%c%s", dir, osSlash, GetFileNameWithoutExt(f)));
		files = rpakLoadFileInfos(pak, &fileCount);

		SetWindowTitle(TextFormat("%s v%s - %s", toolName, toolVersion, pak));

		return false;
	}

	return true;
}

bool addFile(const char *dir, const char *file)
{
	const char *f = TextFormat("%s%c%s", dir, osSlash, file);

	if (FileExists(f))
	{
		files = realloc(files, (fileCount + 1) * sizeof(rpakFileInfo));
		TextCopy((char *)files[fileCount].fileName, file);
		rpakFileType type = rpakGetFileType(f);
		files[fileCount].fileType = type;
		files[fileCount].compressed = true;
		files[fileCount].crypted = type == rpakFileType_Text ? true : false;
		fileCount++;

		if (TextLength(pak) > 0)
			SetWindowTitle(TextFormat("%s v%s - %s*", toolName, toolVersion, pak));

		return false;
	}

	return true;
}

bool addFolder(const char *pdir, const char *dir)
{
	const char *cdir = TextFormat("%s%c%s", pdir, osSlash, dir);

	if (DirectoryExists(cdir))
	{
		FilePathList fs = LoadDirectoryFilesEx(cdir, NULL, true);
		if (fs.count > 0)
		{
			files = realloc(files, (fileCount + fs.count) * sizeof(rpakFileInfo));
			int len = TextLength(pdir);
			for (int i = 0; i < fs.count; i++)
			{
				const char *f = TextSubtext(fs.paths[i], len + 1, TextLength(fs.paths[i]) - len);
				TextCopy((char *)files[fileCount + i].fileName, f);
				rpakFileType type = rpakGetFileType(f);
				files[fileCount + i].fileType = type;
				files[fileCount + i].compressed = true;
				files[fileCount + i].crypted = type == rpakFileType_Text ? true : false;
			}
			fileCount += fs.count;
		}
		UnloadDirectoryFiles(fs);

		if (TextLength(pak) > 0)
			SetWindowTitle(TextFormat("%s v%s - %s*", toolName, toolVersion, pak));

		return false;
	}

	return true;
}

bool exportFile(const char *dir, const char *file)
{
	bool r = true;

	if (DirectoryExists(dir))
	{
		const char *f = TextFormat("%s%c%s", dir, osSlash, file);
		const char *d = GetPrevDirectoryPath(f);
		if (!DirectoryExists(d))
			MakeDirectory(d);

		rpakChunk chk = rpakLoadChunk(file, pak);
		if (chk.data != NULL)
		{
			SaveFileData(f, chk.data, chk.info.baseSize);
			rpakUnloadChunk(chk);
			r = false;
		}
	}

	return r;
}

bool savePackage(const char *dir, const char *file)
{
	if (IsFileExtension(file, RPAK_FILEEXT_INDEX))
	{
		TextCopy(pak, TextFormat("%s%c%s", dir, osSlash, GetFileNameWithoutExt(file)));
		rpakPackFiles(files, fileCount, pak);
		files = rpakLoadFileInfos(pak, &fileCount);

		SetWindowTitle(TextFormat("%s v%s - %s", toolName, toolVersion, pak));

		return false;
	}

	return true;
}
//--------------------------------------------------------------------------------

#ifdef __cplusplus
}
#endif // __cplusplus

int main(int argc, char *argv[])
{
#ifndef _DEBUG
	SetTraceLogLevel(LOG_NONE); // 关闭raylib日志输出
#endif // _DEBUG

	int width = 1280, height = 720;

	bool showDlg = false, showMsgbox = false;
	const char *helpLines[] =
	{
		"F1 - Show / Hide Help Window",
		"F2 - Show / Hide Info Window",
		"-File Controls",
		"LCTRL + N - Create New Package",
		"LCTRL + O - Open Package File",
		"-Edit Controls",
		"LCTRL + F - Add File",
		"LCTRL + D - Add Folder",
		"DELETE - Remove File",
		"LCTRL + E - Export File",
		"-Tool Controls",
		"LCTRL + S - Save Package File"
	};
	const char *infoLines[] =
	{
		"Management Utility for rpak",
		"Source Code: gitee.com/stormdesign/rpak",
		"Contact: stormdesign168@msn.com",
		"-Powered by",
		"raylib: github.com/raysan5/raylib",
		"raygui: github.com/raysan5/raygui",
		"Website: www.raylib.com"
	};

	InitWindow(width, height, TextFormat("%s v%s", toolName, toolVersion));

#ifdef _WIN32
	Image ico = LoadImage(TextFormat("%s.png", toolName));
	SetWindowIcon(ico);
	UnloadImage(ico);
#endif // _WIN32

	SetExitKey(0);
	SetTargetFPS(60);

	Rectangle toolbarRec = (Rectangle) { 0, 0, width, 36 };
	Rectangle statusbarRec = (Rectangle) { 0, height - 26, width, 26 };
	Rectangle tableRec = (Rectangle) { 0, toolbarRec.height, width, height - toolbarRec.height - statusbarRec.height };
	Rectangle dlgRec = (Rectangle) { (width - 640) / 2.f, (height - 360) / 2.f, 640, 360 };

	ToolbarState toolbarState = initToolbar(&toolbarRec);
	TableState tableState = initTable(&tableRec);
	DialogState dlgState = initDialogState();
	MsgboxState msgboxState;

	int helpLinesCount = sizeof(helpLines) / sizeof(helpLines[0]);
	SWindowState helpWinState = initSWinState(width, height, 320, helpLines, helpLinesCount);
	int infoLinesCount = sizeof(infoLines) / sizeof(infoLines[0]);
	SWindowState infoWinState = initSWinState(width, height, 360, infoLines, infoLinesCount);

	while (!WindowShouldClose())
	{
		if ((toolbarState.btnNewPressed || (IsKeyDown(KEY_LEFT_CONTROL) && IsKeyPressed(KEY_N))) && fileCount > 0 && !showMsgbox)
		{
			msgboxState.rec = (Rectangle) { (width - 300) / 2.f, (height - 120) / 2.f, 300, 120 };
			msgboxState.title = "Create Package",
			msgboxState.msg = "Clear all data and create a new empty package?";
			msgboxState.work = createPackage;

			showDlg = false;
			showMsgbox = true;
			helpWinState.windowActive = false;
			infoWinState.windowActive = false;
		}
		else if ((toolbarState.btnOpenPressed || (IsKeyDown(KEY_LEFT_CONTROL) && IsKeyPressed(KEY_O))) && !showDlg)
		{
			dlgState.title = "Select a package file";
			TextCopy(dlgState.tbxDir, dlgState.root);
			TextCopy(dlgState.tbxName, TextFormat("*%s", RPAK_FILEEXT_INDEX));
			dlgState.listUsed = true;
			dlgState.listScrollIdx = 0;
			dlgState.listActive = -1;
			dlgState.listItems = getListItems(dlgState.tbxDir);
			dlgState.work = openPackage;

			showDlg = true;
			showMsgbox = false;
			helpWinState.windowActive = false;
			infoWinState.windowActive = false;
		}
		else if ((toolbarState.btnFilePressed || (IsKeyDown(KEY_LEFT_CONTROL) && IsKeyPressed(KEY_F))) && !showDlg)
		{
			dlgState.title = "Select file";
			TextCopy(dlgState.tbxDir, dlgState.root);
			TextCopy(dlgState.tbxName, "*.*");
			dlgState.listUsed = true;
			dlgState.listScrollIdx = 0;
			dlgState.listActive = -1;
			dlgState.listItems = getListItems(dlgState.tbxDir);
			dlgState.work = addFile;

			showDlg = true;
			showMsgbox = false;
			helpWinState.windowActive = false;
			infoWinState.windowActive = false;
		}
		else if ((toolbarState.btnFolderPressed || (IsKeyDown(KEY_LEFT_CONTROL) && IsKeyPressed(KEY_D))) && !showDlg)
		{
			dlgState.title = "Select folder";
			TextCopy(dlgState.tbxDir, dlgState.root);
			TextCopy(dlgState.tbxName, "*");
			dlgState.listUsed = true;
			dlgState.listScrollIdx = 0;
			dlgState.listActive = -1;
			dlgState.listItems = getListItems(dlgState.tbxDir);
			dlgState.work = addFolder;

			showDlg = true;
			showMsgbox = false;
			helpWinState.windowActive = false;
			infoWinState.windowActive = false;
		}
		else if ((toolbarState.btnDeletePressed || IsKeyPressed(KEY_DELETE)) && fileCount > 0 && !showMsgbox)
		{
			msgboxState.rec = (Rectangle) { (width - 280) / 2.f, (height - 120) / 2.f, 280, 120 };
			msgboxState.title = "Delete File";
			msgboxState.msg = "Remove selected file from package?";
			msgboxState.work = deleteFile;

			showDlg = false;
			showMsgbox = true;
			helpWinState.windowActive = false;
			infoWinState.windowActive = false;
		}
		else if ((toolbarState.btnExportPressed || (IsKeyDown(KEY_LEFT_CONTROL) && IsKeyPressed(KEY_E))) && TextLength(pak) > 0 && fileCount > 0 && !showDlg)
		{
			dlgState.title = "Export file";
			TextCopy(dlgState.tbxDir, dlgState.root);
			TextCopy(dlgState.tbxName, (char *)files[tableState.selectedIdx].fileName);
			dlgState.listUsed = false;
			dlgState.listScrollIdx = 0;
			dlgState.listActive = -1;
			dlgState.listItems = getListItems(dlgState.tbxDir);
			dlgState.work = exportFile;

			showDlg = true;
			showMsgbox = false;
			helpWinState.windowActive = false;
			infoWinState.windowActive = false;
		}
		else if ((toolbarState.btnSavePressed || (IsKeyDown(KEY_LEFT_CONTROL) && IsKeyPressed(KEY_S))) && fileCount > 0 && !showDlg)
		{
			dlgState.title = "Save package file";
			if (TextLength(pak) > 0)
			{
				const char *f = TextFormat("%s%s", pak, RPAK_FILEEXT_INDEX);
				TextCopy(dlgState.tbxDir, GetPrevDirectoryPath(f));
				TextCopy(dlgState.tbxName, GetFileName(f));
			}
			else
			{
				TextCopy(dlgState.tbxDir, dlgState.root);
				TextCopy(dlgState.tbxName, TextFormat("rpak%s", RPAK_FILEEXT_INDEX));
			}
			dlgState.listUsed = false;
			dlgState.listScrollIdx = 0;
			dlgState.listActive = -1;
			dlgState.listItems = getListItems(dlgState.tbxDir);
			dlgState.work = savePackage;

			showDlg = true;
			showMsgbox = false;
			helpWinState.windowActive = false;
			infoWinState.windowActive = false;
		}
		else if (toolbarState.btnHelpPressed || IsKeyPressed(KEY_F1))
		{
			helpWinState.windowActive = !helpWinState.windowActive;
			if (helpWinState.windowActive)
			{
				showDlg = false;
				showMsgbox = false;
				infoWinState.windowActive = false;
			}
		}
		else if (toolbarState.btnInfoPressed || IsKeyPressed(KEY_F2))
		{
			infoWinState.windowActive = !infoWinState.windowActive;
			if (infoWinState.windowActive)
			{
				showDlg = false;
				showMsgbox = false;
				helpWinState.windowActive = false;
			}
		}

		BeginDrawing();
		{
			ClearBackground((Color) { 215, 215, 215, 255 });

			if (showDlg || showMsgbox || helpWinState.windowActive || infoWinState.windowActive)
				GuiLock();
			drawStatusbar(&statusbarRec,
			              fileCount > 0 ? tableState.selectedIdx + 1 : 0,
			              fileCount,
			              fileCount > 0 ? files[tableState.selectedIdx].offset : 0,
			              fileCount > 0 ? files[tableState.selectedIdx].baseSize : 0,
			              fileCount > 0 ? files[tableState.selectedIdx].packedSize : 0);
			drawTable(&tableState, files, fileCount);
			drawToolbar(&toolbarState);
			if (showDlg || showMsgbox || helpWinState.windowActive || infoWinState.windowActive)
				GuiUnlock();

			if (showDlg)
				showDlg = GuiDialog(&dlgRec, &dlgState);
			if (showMsgbox)
				showMsgbox = GuiMsgbox(&msgboxState, &fileCount, &tableState.selectedIdx);
			drawSWindow(&helpWinState, width, height, "#193#Help", helpLines, helpLinesCount);
			drawSWindow(&infoWinState, width, height, "#191#Info", infoLines, infoLinesCount);
		}
		EndDrawing();
	}

	rpakUnloadFileInfos(files, fileCount);

	CloseWindow();

	return 0;
}